package epoch.db.gamedb;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * ModelBuilder.
 */
public class EntityBuilder {
	

	public static final <T extends Entity> List<T> build(ResultSet rs, Class<? extends Entity> modelClass) throws SQLException, InstantiationException, IllegalAccessException {
		return buildPaginate(rs,modelClass,Integer.MAX_VALUE);
	}
	
	@SuppressWarnings("unchecked")
	public static final <T> List<T> buildPaginate(ResultSet rs, Class<? extends Entity> modelClass, int pageSize) throws SQLException, InstantiationException, IllegalAccessException {
		List<T> result = new ArrayList<T>();
		ResultSetMetaData rsmd = rs.getMetaData();
		int columnCount = rsmd.getColumnCount();
		String[] labelNames = new String[columnCount + 1];
		int[] types = new int[columnCount + 1];
		buildLabelNamesAndTypes(rsmd, labelNames, types);
		for (int k=0; k<pageSize && rs.next(); k++) {
			Entity entity = modelClass.newInstance();
			Map<String, Object> attrs = entity.getAttrs();
			for (int i=1; i<=columnCount; i++) {
				Object value;
				if(types[i]==Types.TINYINT){
					value = rs.getByte(i);
				}else if(types[i]==Types.SMALLINT){
					value = rs.getShort(i);
				}else if (types[i] < Types.BLOB) {
					value = rs.getObject(i);
				} else if (types[i] == Types.CLOB) {
					value = EntityBuilder.handleClob(rs.getClob(i));
				} else if (types[i] == Types.NCLOB) {
					value = EntityBuilder.handleClob(rs.getNClob(i));
				} else if (types[i] == Types.BLOB) {
					value = EntityBuilder.handleBlob(rs.getBlob(i));
				} else {
					value = rs.getObject(i);
				}
				if(value!=null){//为null时不用填充值
					attrs.put(labelNames[i], value);
				}
			}
			result.add((T)entity);
		}
		return result;
	}
	
	private static final void buildLabelNamesAndTypes(ResultSetMetaData rsmd, String[] labelNames, int[] types) throws SQLException {
		for (int i=1; i<labelNames.length; i++) {
			labelNames[i] = rsmd.getColumnLabel(i);
			types[i] = rsmd.getColumnType(i);
		}
	}
	
	public static byte[] handleBlob(Blob blob) throws SQLException {
		if (blob == null)
			return null;
		
		InputStream is = null;
		try {
			is = blob.getBinaryStream();
			if (is == null)
				return null;
			byte[] data = new byte[(int)blob.length()];		// byte[] data = new byte[is.available()];
			if (data.length == 0)
				return null;
			is.read(data);
			return data;
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		finally {
			if (is != null)
				try {is.close();} catch (IOException e) {throw new RuntimeException(e);}
		}
	}
	
	public static String handleClob(Clob clob) throws SQLException {
		if (clob == null)
			return null;

		Reader reader = null;
		try {
			reader = clob.getCharacterStream();
			if (reader == null)
				return null;
			char[] buffer = new char[(int)clob.length()];
			if (buffer.length == 0)
				return null;
			reader.read(buffer);
			return new String(buffer);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		finally {
			if (reader != null)
				try {reader.close();} catch (IOException e) {throw new RuntimeException(e);}
		}
	}
}

